from sys import argv
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *


class MyPyOpenGLTest:
    # 初始化OpenGL环境，指定显示模式以及用于绘图的函数
    def __init__(self, width=640, height=480,
                 title='PyOpenGL旋转立方体'.encode('gbk')):
        glutInit(argv)
        # 使用RGBA颜色、双缓冲、深度缓冲Z-Buffer
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        # 设置图形窗口初始大小和位置，然后创建图形窗口，顺序不能变
        glutInitWindowSize(width, height)
        glutInitWindowPosition(400, 200)
        glutCreateWindow(title)
        # 指定绘制图形时执行的方法
        glutDisplayFunc(self.draw)
        # 指定调整窗口大小时执行的方法
        glutReshapeFunc(self.reshape)
        # 指定系统空闲时执行的方法，是本动画的重要基础
        glutIdleFunc(self.draw)

        # 表示旋转角度的数据成员，整个类中都可以使用
        self.angle = 0.0

        # 进一步初始化，完成个性化设置
        self.InitGL(width, height)

    # 根据特定的需要，进一步完成OpenGL的初始化
    def InitGL(self, width, height):
        # 设置光源0的位置
        # 仅在当前方法中使用，定义为局部变量可以减小开销
        light_position = (1.0, 1.0, 1.0)
        glLightfv(GL_LIGHT0, GL_POSITION, light_position)
        # 设置光源0的RGBA四个分量漫反射程度
        light_ambient = (0.3, 0.9, 0.9, 1.0)
        glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient)

        # 初始化窗口背景为黑色
        glClearColor(0.0, 0.0, 0.0, 1.0)
        # 启用纵深测试，设置深度，注意线框立方体旋转时远处消失的效果
        glClearDepth(0.9)
        glEnable(GL_DEPTH_TEST)
        # 其他可取的值还有GL_NEVER、GL_EQUAL、GL_LEQUAL、GL_GREATER、
        # GL_NOTEQUAL、GL_GEQUAL、GL_ALWAYS
        glDepthFunc(GL_LESS)

        # 设置光滑渲染
        glEnable(GL_BLEND)
        glShadeModel(GL_SMOOTH)
        glEnable(GL_POINT_SMOOTH)
        glEnable(GL_LINE_SMOOTH)
        glEnable(GL_POLYGON_SMOOTH)
        # 设置反走样/抗锯齿算法
        glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)
        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
        glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST)

        # 切换到透视投影矩阵
        glMatrixMode(GL_PROJECTION)
        # 加载单位矩阵，重置
        glLoadIdentity()
        # 参数分别表示角度、宽/高比、视景体近处zNear、视景体远处zFar
        gluPerspective(45, width / height, 1, 10)

        # 切换到模型观察矩阵，参数可能的取值还有GL_TEXTURE
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

    # 调整图形窗口大小时执行的方法
    def reshape(self, w, h):
        if h == 0:
            h = 1
        ratio = w / h
        glViewport(0, 0, w, h)

        # 切换到透视投影矩阵
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45, ratio, 1, 10)
        # 切换到模型观察矩阵
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

    # 自己的绘图方法，本程序的关键
    def draw(self):
        # 每次绘制图形之前清除颜色缓冲区和深度缓冲区中的信息
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 设置颜色红、绿、蓝分量值
        glColor3f(0.8, 0.8, 0.1)
        # 切换到模型观察矩阵，才能正确绘制图形
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        # 沿x、z轴平移
        glTranslatef(-1.0, 0.0, -5.0)
        # 沿y轴和z轴旋转
        # 第一个参数表示旋转角度，后面三个参数表示旋转轴
        glRotatef(self.angle, 0, 1, 1)
        # 绘制线框立方体，参数表示边长
        glutWireCube(1.5)

        # 修改颜色
        glColor3f(0.8, 0.3, 1)
        # 绘制实心立方体之前启用光照效果
        # OpenGL预置8个光源，分别为GL_LIGHT0-7
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        glLoadIdentity()
        glTranslatef(1.0, 0.0, -5.0)
        glRotatef(-self.angle, 0, 1, 1)
        # 绘制实心立方体
        glutSolidCube(1)
        # 关闭光照效果，使得光照效果仅作用于当前实心立方体
        glDisable(GL_LIGHTING)

        # 修改旋转角度，修改步幅大小可以调整立方体旋转速度
        self.angle = self.angle + 0.03

        # 交换缓冲区，更新图形
        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()


if __name__ == '__main__':
    # 创建窗口对象，启动消息主循环
    MyPyOpenGLTest().mainloop()
